package com.mukesh;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.BlendMode;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.ImagePacker;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.render.Canvas;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.render.Texture;

public class DrawingView extends Component implements Component.DrawTask, Component.TouchEventListener {

    private static final float TOUCH_TOLERANCE = 4;
    private PixelMap pixelMap;
    private Path path;
    private Paint bitmapPaint;
    private Paint paint;
    private boolean drawMode;
    private float mX;
    private float mY;
    private float penSize = 10;
    private float eraserSize = 10;
    private int colors;
    private RectFloat rect;
    private Color paintColor = Color.BLACK;
    private ArrayList<PaintPathBean> paths = new ArrayList<>();
    private boolean isTouch = false;

    public DrawingView(Context context) {
        this(context, null);
    }

    public DrawingView(Context context, AttrSet attrSet) {
        this(context, attrSet, 0);
    }

    public DrawingView(Context context, AttrSet attrSet, int styleName) {
        super(context, attrSet, styleName);
        init();
    }

    private void init() {
        addDrawTask(this);
        colors = Color.rgb(255, 255, 255);
        setTouchEventListener(this);

        path = new Path();
        bitmapPaint = new Paint();
        paint = creatPaint();
        drawMode = true;


        rect = new RectFloat();
    }

    private Paint creatPaint() {
        Paint newPaint = new Paint();
        newPaint.setAntiAlias(true);
        newPaint.setDither(true);
        if (drawMode) {
            newPaint.setColor(paintColor);
        }
        newPaint.setStyle(Paint.Style.STROKE_STYLE);
        newPaint.setStrokeJoin(Paint.Join.ROUND_JOIN);
        newPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        newPaint.setStrokeWidth(drawMode ? penSize : eraserSize);
        newPaint.setBlendMode(BlendMode.SRC);
        return newPaint;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        rect.left = 0;
        rect.top = 0;
        rect.bottom = getHeight();
        rect.right = getWidth();
        canvas.drawColor(colors, Canvas.PorterDuffMode.SRC);
        if (pixelMap != null) {
            PixelMapHolder pixelMapHolder = new PixelMapHolder(pixelMap);
            canvas.drawPixelMapHolder(pixelMapHolder, 0, 0, bitmapPaint);
        }

        int layerId = canvas.saveLayer(rect, bitmapPaint);
        paths.forEach(paintPathBean -> {
            canvas.drawPath(paintPathBean.getPath(), paintPathBean.getPaint());
        });
        if (isTouch) {
            canvas.drawPath(path, paint);
        }

        canvas.restoreToCount(layerId);
    }

    /**
     * 放大  宽度为控件宽度,从新设置PixelMap 的宽高
     *
     * @param pixelMap PixelMap
     * @return PixelMap
     */
    private PixelMap getPicMapRect(PixelMap pixelMap) {
        Size size = pixelMap.getImageInfo().size;
        int width = size.width;
        int height = size.height;
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.size = new Size(getWidth(), height * getWidth() / width);
        options.pixelFormat = PixelFormat.ARGB_8888;
        options.editable = true;
        return PixelMap.create(pixelMap, options);
    }

    private void touchStart(float x, float y) {
        isTouch = true;
        path = new Path();
        path.moveTo(x, y);
        this.mX = x;
        this.mY = y;
    }

    private void touchMove(float x, float y) {
        float dx = (float) Math.abs((double) x - this.mX);
        float dy = (float) Math.abs((double) y - this.mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            path.quadTo(this.mX, this.mY, (float) (((double) x + this.mX) / 2), (float) (((double) y + this.mY) / 2));
            this.mX = x;
            this.mY = y;
        }
    }

    private void touchUp() {
        isTouch = false;
        path.lineTo(mX, mY);

        PaintPathBean paintPathBean = new PaintPathBean(path, paint);
        paths.add(paintPathBean);
        paint = creatPaint();
        if (drawMode) {
            paint.setBlendMode(BlendMode.SRC);
        } else {
            paint.setBlendMode(BlendMode.CLEAR);
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        MmiPoint point = touchEvent.getPointerPosition(touchEvent.getIndex());
        float xPoint = point.getX();
        float yPoint = point.getY();
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                if (!drawMode) {
                    paint.setBlendMode(BlendMode.CLEAR);
                } else {
                    paint.setBlendMode(BlendMode.SRC);
                }
                touchStart(xPoint, yPoint);
                invalidate();
                break;
            case TouchEvent.POINT_MOVE:
                touchMove(xPoint, yPoint);
                invalidate();
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                touchUp();
                invalidate();
                break;
            default:
                break;
        }
        return true;
    }

    public void initializePen() {
        drawMode = true;
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setColor(paintColor);
        paint.setStyle(Paint.Style.STROKE_STYLE);
        paint.setStrokeJoin(Paint.Join.ROUND_JOIN);
        paint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        paint.setStrokeWidth(penSize);
        paint.setBlendMode(BlendMode.SRC);
    }

    public void initializeEraser() {
        drawMode = false;
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE_STYLE);
        paint.setStrokeWidth(eraserSize);
        paint.setBlendMode(BlendMode.CLEAR);
    }

    public void clear() {
        path.reset();
        paths.clear();
        pixelMap = null;
        invalidate();
    }

    public void setBackgroundColor(int color) {
        colors = color;
        invalidate();
    }


    public void setEraserSize(float size) {
        eraserSize = size;
        initializeEraser();
    }

    public void setPenSize(float size) {
        penSize = size;
        initializePen();
    }

    public float getEraserSize() {
        return eraserSize;
    }

    public float getPenSize() {
        return penSize;
    }

    public void setPenColor(int color) {
        paintColor = new Color(color);
        paint.setColor(paintColor);
    }

    public Color getPenColor() {
        return paint.getColor();
    }

    public void loadImage(PixelMap pixelMap) {
        paths.clear();
        PixelMap picMapRect = getPicMapRect(pixelMap);
        this.pixelMap = picMapRect;

        invalidate();
    }

    private PixelMap savePic;

    public boolean saveImage(String filePath, String filename, int quality) {
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.size = new Size(getEstimatedWidth(), getEstimatedHeight());
        options.pixelFormat = PixelFormat.ARGB_8888;
        options.editable = true;
        savePic = PixelMap.create(options);
        Canvas canvas = new Canvas(new Texture(savePic));
        canvas.drawColor(this.colors, Canvas.PorterDuffMode.SRC);
        if (pixelMap != null) {
            PixelMapHolder pixelMapHolder = new PixelMapHolder(pixelMap);
            canvas.drawPixelMapHolder(pixelMapHolder, 0, 0, bitmapPaint);
        }
        int layerId = canvas.saveLayer(rect, bitmapPaint);
        paths.forEach(paintPathBean -> {
            canvas.drawPath(paintPathBean.getPath(), paintPathBean.getPaint());
        });
        canvas.restoreToCount(layerId);
        PixelMapHolder pixelMapHolder = new PixelMapHolder(savePic);
        canvas.drawPixelMapHolder(pixelMapHolder, 0, 0, bitmapPaint);
        if (quality > 100) {
            return false;
        }
        File file = new File(filePath + filename);
        FileOutputStream out = null;
        ImagePacker packer = null;
        try {
            out = new FileOutputStream(file);
            ImagePacker.PackingOptions opt = new ImagePacker.PackingOptions();
            opt.format = "image/jpeg";
            opt.quality = quality;
            packer = ImagePacker.create();
            boolean result = packer.initializePacking(out, opt);
            result = packer.addImage(savePic);
            long dataSize = packer.finalizePacking();
            return dataSize > 0;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (packer != null) {
                    packer.release();
                }
                if (out != null) {
                    out.flush();
                    out.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

